討論以下三種排列方式的布局元件:
1.垂直排列
2.橫向排列
3.網格排列
比較類似功能的布局元件,於 Kotlin & Flutter 間的實作差異
Kotlin | Flutter |
---|---|
使用LinearLayout orientation="vertical"
調整兩個 layout 檔案
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/TitleTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text = "LinearLayout (vertical) "
android:textSize = "20dp"
android:textColor= "@color/black"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/TitleTV"
>
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
card_item.xml
: 此 layout 會沿用下列其他範例<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="10dp"
app:contentPadding="5dp"
android:layout_margin="10dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:text="My book"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:textColor= "@color/black"
android:textSize="20dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="120dp"
android:layout_height="80dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView"
app:srcCompat="@drawable/image_book" />
<ImageView
android:id="@+id/imageViewButton"
android:layout_width="45dp"
android:layout_height="45dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imageView"
app:srcCompat="@drawable/star"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
使用 Column
元件
修改
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<StatefulWidget> {
///是否點擊收藏按鈕
bool bIsCollectBook = false;
@override
Widget build(BuildContext context) {
///由上到下垂直排列元件 list
List<Widget> _widgetList = [
_wTitle("My book"),
_wBookImage("asset/image_book.jpg"),
_wButtonForCollectBook(bIsCollect: bIsCollectBook)
];
///圓角框元件內容
Widget _wCardContent = Container(
padding: EdgeInsets.symmetric(vertical: 5,horizontal: 3),
constraints: BoxConstraints(maxWidth: 120),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: _widgetList,
));
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: _wAppBar(),
body: Container(
alignment: Alignment.center,
color: Colors.lightGreen.withOpacity(0.5),
child: Column(children: [
_wCardItem(_wCardContent),_wCardItem(_wCardContent),_wCardItem(_wCardContent)]),
)));
}
PreferredSizeWidget _wAppBar(){
return AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: Text("Column",style: TextStyle(color:Colors.black,fontSize: 30,letterSpacing: 2,decoration: TextDecoration.underline),),
elevation: 0,
);
}
Widget _wCardItem(Widget wItem){
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: wItem,
);
}
///標題元件
Widget _wTitle(String sTitle){
return Text(
"$sTitle",
style: TextStyle(fontSize: 18,fontWeight: FontWeight.w500),
textAlign: TextAlign.start,
);
}
///書籍圖片元件
Widget _wBookImage(String sImagePath){
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 10),
child: Image.asset(
"$sImagePath",
height: 120,
width: 80,
),
);
}
///收藏書籍按鈕元件
Widget _wButtonForCollectBook({bool bIsCollect = false}){
String sImagePath = bIsCollect ? "asset/star_select.png":"asset/star_unselect.png";
return Container(
alignment: Alignment.center,
child: InkWell(
onTap: () {
///點擊收藏書籍按鈕, 改變按鈕狀態 flag , 進而改變按鈕顏色
setState(() {
bIsCollectBook = !bIsCollectBook;
});
},
child: Image.asset(
"$sImagePath",
height: 45,
width: 45,
)),
);
}
}
Kotlin | Flutter |
---|---|
使用 LinearLayout orientation="horizontal"
修改一個layout檔案
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/TitleTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:text = "LinearLayout (horizontal) "
android:textSize = "20dp"
android:textColor= "@color/black"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/TitleTV"
>
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
使用 Row
元件
修改
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<StatefulWidget> {
///是否點擊收藏按鈕
bool bIsCollectBook = false;
@override
Widget build(BuildContext context) {
///由上到下垂直排列元件 list
List<Widget> _widgetList = [
_wTitle("My book"),
_wBookImage("asset/image_book.jpg"),
_wButtonForCollectBook(bIsCollect: bIsCollectBook)
];
///圓角框元件內容
Widget _wCardContent = Container(
padding: EdgeInsets.symmetric(vertical: 5,horizontal: 3),
constraints: BoxConstraints(maxWidth: 120),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: _widgetList,
));
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: _wAppBar(),
body: Container(
alignment: Alignment.center,
color: Colors.lightGreen.withOpacity(0.5),
child: Row(children: [
_wCardItem(_wCardContent),_wCardItem(_wCardContent),_wCardItem(_wCardContent)]),
)));
}
PreferredSizeWidget _wAppBar(){
return AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: Text("Row",style: TextStyle(color:Colors.black,fontSize: 30,letterSpacing: 2,decoration: TextDecoration.underline),),
elevation: 0,
);
}
Widget _wCardItem(Widget wItem){
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: wItem,
);
}
///標題元件
Widget _wTitle(String sTitle){
return Text(
"$sTitle",
style: TextStyle(fontSize: 18,fontWeight: FontWeight.w500),
textAlign: TextAlign.start,
);
}
///書籍圖片元件
Widget _wBookImage(String sImagePath){
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 10),
child: Image.asset(
"$sImagePath",
height: 120,
width: 80,
),
);
}
///收藏書籍按鈕元件
Widget _wButtonForCollectBook({bool bIsCollect = false}){
String sImagePath = bIsCollect ? "asset/star_select.png":"asset/star_unselect.png";
return Container(
alignment: Alignment.center,
child: InkWell(
onTap: () {
///點擊收藏書籍按鈕, 改變按鈕狀態 flag , 進而改變按鈕顏色
setState(() {
bIsCollectBook = !bIsCollectBook;
});
},
child: Image.asset(
"$sImagePath",
height: 45,
width: 45,
)),
);
}
}
Kotlin | Flutter |
---|---|
使用 GridLayout
修改一個layout檔案
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/TitleTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="GridView"
android:textColor="@color/black"
android:textSize="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<GridLayout
android:id="@+id/GridLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/TitleTV"
>
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
<include layout="@layout/card_item" />
</GridLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
使用 GridView
元件
修改
main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<StatefulWidget> {
///是否點擊收藏按鈕
bool bIsCollectBook = false;
@override
Widget build(BuildContext context) {
///由上到下垂直排列元件 list
List<Widget> _widgetList = [
_wTitle("My book"),
_wBookImage("asset/image_book.jpg"),
_wButtonForCollectBook(bIsCollect: bIsCollectBook)
];
///圓角框元件內容
Widget _wCardContent = Container(
padding: EdgeInsets.symmetric(vertical: 5,horizontal: 3),
constraints: BoxConstraints(maxWidth: 120),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: _widgetList,
));
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: _wAppBar(),
body: Container(
alignment: Alignment.center,
color: Colors.lightGreen.withOpacity(0.5),
child: GridView.count(
crossAxisCount: 2,
childAspectRatio: 0.9,
children: [
_wCardItem(_wCardContent),_wCardItem(_wCardContent),_wCardItem(_wCardContent)]),
)));
}
PreferredSizeWidget _wAppBar(){
return AppBar(
backgroundColor: Colors.white,
centerTitle: true,
title: Text("GridVeiw",style: TextStyle(color:Colors.black,fontSize: 30,letterSpacing: 2,decoration: TextDecoration.underline),),
elevation: 0,
);
}
Widget _wCardItem(Widget wItem){
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: wItem,
);
}
///標題元件
Widget _wTitle(String sTitle){
return Text(
"$sTitle",
style: TextStyle(fontSize: 18,fontWeight: FontWeight.w500),
textAlign: TextAlign.start,
);
}
///書籍圖片元件
Widget _wBookImage(String sImagePath){
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 10,vertical: 10),
child: Image.asset(
"$sImagePath",
height: 120,
width: 80,
),
);
}
///收藏書籍按鈕元件
Widget _wButtonForCollectBook({bool bIsCollect = false}){
String sImagePath = bIsCollect ? "asset/star_select.png":"asset/star_unselect.png";
return Container(
alignment: Alignment.center,
child: InkWell(
onTap: () {
///點擊收藏書籍按鈕, 改變按鈕狀態 flag , 進而改變按鈕顏色
setState(() {
bIsCollectBook = !bIsCollectBook;
});
},
child: Image.asset(
"$sImagePath",
height: 45,
width: 45,
)),
);
}
}